package com.hightrast.service.util;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MybatisPlusGenerator {
    public MybatisPlusGenerator() {
    }


    public static void execute(MybatisPlusGenerator.GeneratorModel generatorModel) throws IOException {
        if (generatorModel.getOutputDir() == null || "".equals(generatorModel.getOutputDir())) {
            File file = new File(MybatisPlusGenerator.class.getClass().getResource("/").getPath());
            generatorModel.setOutputDir(file.getCanonicalPath().split("target")[0]);
        }

        AutoGenerator mpg = new AutoGenerator();
        mpg.setGlobalConfig(buildGlobalConfig(generatorModel.getOutputDir(), generatorModel));
        mpg.setDataSource(buildDataSourceConfig(generatorModel));
        PackageConfig pc = buildPackageConfig(generatorModel.getParent(), generatorModel.getModuleName());
        mpg.setPackageInfo(pc);
        mpg.setCfg(buildInjectionConfig(generatorModel.getOutputDir(), pc.getModuleName()));
        mpg.setStrategy(buildStrategyConfig(generatorModel));
        mpg.setTemplate((new TemplateConfig()).setXml((String)null));
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

    public static PackageConfig buildPackageConfig(String parent, String moduleName) {
        PackageConfig pc = new PackageConfig();
        pc.setParent(parent);
        pc.setModuleName(moduleName);
        return pc;
    }

    public static GlobalConfig buildGlobalConfig(String projectPath, MybatisPlusGenerator.GeneratorModel generatorModel) {
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(projectPath + "src/main/java");
        gc.setFileOverride(true);
        gc.setBaseResultMap(false);
        gc.setBaseColumnList(true);
        gc.setSwagger2(true);
        gc.setOpen(false);
        gc.setAuthor(generatorModel.getAuthor());
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("I%sService");
        gc.setServiceImplName("%sServiceImpl");
        return gc;
    }

    public static InjectionConfig buildInjectionConfig(final String projectPath, final String moduleName) {
        InjectionConfig cfg = new InjectionConfig() {
            public void initMap() {
            }
        };
        List<FileOutConfig> focList = new ArrayList();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            public String outputFile(TableInfo tableInfo) {
                return moduleName == null ? MessageFormat.format("{0}src/main/resources/mapper/{1}Mapper{2}", projectPath, tableInfo.getEntityName(), ".xml") : MessageFormat.format("{0}src/main/resources/mapper/{1}/{2}Mapper{3}", projectPath, moduleName, tableInfo.getEntityName(), ".xml");
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    private String getRealName(String origin) {
        return origin.replaceFirst("Tf", "").replaceFirst("Ts", "").replaceFirst("Td", "");
    }

    public static DataSourceConfig buildDataSourceConfig(MybatisPlusGenerator.GeneratorModel generatorModel) {
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setDriverName(generatorModel.getDriverName());
        String url = "jdbc:mysql://{0}/{1}?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8";
        dsc.setUrl(MessageFormat.format(url, generatorModel.getAddress(), generatorModel.getStock()));
        dsc.setUsername(generatorModel.getUsername());
        dsc.setPassword(generatorModel.getPassword());
        return dsc;
    }

    public static StrategyConfig buildStrategyConfig(MybatisPlusGenerator.GeneratorModel generatorModel) {
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setFieldPrefix(generatorModel.getFieldPrefix());
        strategy.setTablePrefix(generatorModel.getTablePrefix());
        strategy.setInclude(generatorModel.getInclude());
        strategy.setExclude(generatorModel.getExclude());
        strategy.setSuperEntityClass(generatorModel.getSuperEntityClass());
        strategy.setSuperEntityColumns(generatorModel.getSuperEntityColumns());
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(generatorModel.isControllerMappingHyphenStyle());
        strategy.setEntityTableFieldAnnotationEnable(generatorModel.entityTableFieldAnnotationEnable);
        return strategy;
    }

    public static class GeneratorModel {
        private String author;
        private String parent;
        private String moduleName;
        private String driverName = "com.mysql.jdbc.Driver";
        private String address;
        private String stock;
        private String username;
        private String password;
        private String superEntityClass;
        private String[] superEntityColumns;
        private String[] tablePrefix = new String[]{"tf_", "td_", "ts_", "tl_"};
        private String[] fieldPrefix;
        private String[] include;
        private String[] exclude;
        private boolean controllerMappingHyphenStyle = true;
        private String outputDir;
        private boolean entityTableFieldAnnotationEnable = false;

        public final MybatisPlusGenerator.GeneratorModel build() {
            return new MybatisPlusGenerator.GeneratorModel();
        }

        public final MybatisPlusGenerator.GeneratorModel build(String parent, String moduleName) {
            return this.build().setParent(parent).setModuleName(moduleName);
        }

        public final MybatisPlusGenerator.GeneratorModel build(String address, String stock, String username, String password) {
            return this.build().setAddress(address).setStock(stock).setUsername(username).setPassword(password);
        }

        public GeneratorModel() {
        }

        public String getAuthor() {
            return this.author;
        }

        public String getParent() {
            return this.parent;
        }

        public String getModuleName() {
            return this.moduleName;
        }

        public String getDriverName() {
            return this.driverName;
        }

        public String getAddress() {
            return this.address;
        }

        public String getStock() {
            return this.stock;
        }

        public String getUsername() {
            return this.username;
        }

        public String getPassword() {
            return this.password;
        }

        public String getSuperEntityClass() {
            return this.superEntityClass;
        }

        public String[] getSuperEntityColumns() {
            return this.superEntityColumns;
        }

        public String[] getTablePrefix() {
            return this.tablePrefix;
        }

        public String[] getFieldPrefix() {
            return this.fieldPrefix;
        }

        public String[] getInclude() {
            return this.include;
        }

        public String[] getExclude() {
            return this.exclude;
        }

        public boolean isControllerMappingHyphenStyle() {
            return this.controllerMappingHyphenStyle;
        }

        public String getOutputDir() {
            return this.outputDir;
        }

        public boolean isEntityTableFieldAnnotationEnable() {
            return this.entityTableFieldAnnotationEnable;
        }

        public MybatisPlusGenerator.GeneratorModel setAuthor(final String author) {
            this.author = author;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setParent(final String parent) {
            this.parent = parent;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setModuleName(final String moduleName) {
            this.moduleName = moduleName;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setDriverName(final String driverName) {
            this.driverName = driverName;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setAddress(final String address) {
            this.address = address;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setStock(final String stock) {
            this.stock = stock;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setUsername(final String username) {
            this.username = username;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setPassword(final String password) {
            this.password = password;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setSuperEntityClass(final String superEntityClass) {
            this.superEntityClass = superEntityClass;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setSuperEntityColumns(final String[] superEntityColumns) {
            this.superEntityColumns = superEntityColumns;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setTablePrefix(final String[] tablePrefix) {
            this.tablePrefix = tablePrefix;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setFieldPrefix(final String[] fieldPrefix) {
            this.fieldPrefix = fieldPrefix;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setInclude(final String[] include) {
            this.include = include;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setExclude(final String[] exclude) {
            this.exclude = exclude;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setControllerMappingHyphenStyle(final boolean controllerMappingHyphenStyle) {
            this.controllerMappingHyphenStyle = controllerMappingHyphenStyle;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setOutputDir(final String outputDir) {
            this.outputDir = outputDir;
            return this;
        }

        public MybatisPlusGenerator.GeneratorModel setEntityTableFieldAnnotationEnable(final boolean entityTableFieldAnnotationEnable) {
            this.entityTableFieldAnnotationEnable = entityTableFieldAnnotationEnable;
            return this;
        }

        public boolean equals(final Object o) {
            if (o == this) {
                return true;
            } else if (!(o instanceof MybatisPlusGenerator.GeneratorModel)) {
                return false;
            } else {
                MybatisPlusGenerator.GeneratorModel other = (MybatisPlusGenerator.GeneratorModel)o;
                if (!other.canEqual(this)) {
                    return false;
                } else {
                    label159: {
                        Object this$author = this.getAuthor();
                        Object other$author = other.getAuthor();
                        if (this$author == null) {
                            if (other$author == null) {
                                break label159;
                            }
                        } else if (this$author.equals(other$author)) {
                            break label159;
                        }

                        return false;
                    }

                    Object this$parent = this.getParent();
                    Object other$parent = other.getParent();
                    if (this$parent == null) {
                        if (other$parent != null) {
                            return false;
                        }
                    } else if (!this$parent.equals(other$parent)) {
                        return false;
                    }

                    Object this$moduleName = this.getModuleName();
                    Object other$moduleName = other.getModuleName();
                    if (this$moduleName == null) {
                        if (other$moduleName != null) {
                            return false;
                        }
                    } else if (!this$moduleName.equals(other$moduleName)) {
                        return false;
                    }

                    label138: {
                        Object this$driverName = this.getDriverName();
                        Object other$driverName = other.getDriverName();
                        if (this$driverName == null) {
                            if (other$driverName == null) {
                                break label138;
                            }
                        } else if (this$driverName.equals(other$driverName)) {
                            break label138;
                        }

                        return false;
                    }

                    label131: {
                        Object this$address = this.getAddress();
                        Object other$address = other.getAddress();
                        if (this$address == null) {
                            if (other$address == null) {
                                break label131;
                            }
                        } else if (this$address.equals(other$address)) {
                            break label131;
                        }

                        return false;
                    }

                    Object this$stock = this.getStock();
                    Object other$stock = other.getStock();
                    if (this$stock == null) {
                        if (other$stock != null) {
                            return false;
                        }
                    } else if (!this$stock.equals(other$stock)) {
                        return false;
                    }

                    Object this$username = this.getUsername();
                    Object other$username = other.getUsername();
                    if (this$username == null) {
                        if (other$username != null) {
                            return false;
                        }
                    } else if (!this$username.equals(other$username)) {
                        return false;
                    }

                    label110: {
                        Object this$password = this.getPassword();
                        Object other$password = other.getPassword();
                        if (this$password == null) {
                            if (other$password == null) {
                                break label110;
                            }
                        } else if (this$password.equals(other$password)) {
                            break label110;
                        }

                        return false;
                    }

                    label103: {
                        Object this$superEntityClass = this.getSuperEntityClass();
                        Object other$superEntityClass = other.getSuperEntityClass();
                        if (this$superEntityClass == null) {
                            if (other$superEntityClass == null) {
                                break label103;
                            }
                        } else if (this$superEntityClass.equals(other$superEntityClass)) {
                            break label103;
                        }

                        return false;
                    }

                    if (!Arrays.deepEquals(this.getSuperEntityColumns(), other.getSuperEntityColumns())) {
                        return false;
                    } else if (!Arrays.deepEquals(this.getTablePrefix(), other.getTablePrefix())) {
                        return false;
                    } else if (!Arrays.deepEquals(this.getFieldPrefix(), other.getFieldPrefix())) {
                        return false;
                    } else if (!Arrays.deepEquals(this.getInclude(), other.getInclude())) {
                        return false;
                    } else if (!Arrays.deepEquals(this.getExclude(), other.getExclude())) {
                        return false;
                    } else if (this.isControllerMappingHyphenStyle() != other.isControllerMappingHyphenStyle()) {
                        return false;
                    } else {
                        Object this$outputDir = this.getOutputDir();
                        Object other$outputDir = other.getOutputDir();
                        if (this$outputDir == null) {
                            if (other$outputDir != null) {
                                return false;
                            }
                        } else if (!this$outputDir.equals(other$outputDir)) {
                            return false;
                        }

                        if (this.isEntityTableFieldAnnotationEnable() != other.isEntityTableFieldAnnotationEnable()) {
                            return false;
                        } else {
                            return true;
                        }
                    }
                }
            }
        }

        protected boolean canEqual(final Object other) {
            return other instanceof MybatisPlusGenerator.GeneratorModel;
        }

        public int hashCode() {
//            int PRIME = true;
            int result = 1;
            Object $author = this.getAuthor();
//            int result = result * 59 + ($author == null ? 43 : $author.hashCode());
            Object $parent = this.getParent();
            result = result * 59 + ($parent == null ? 43 : $parent.hashCode());
            Object $moduleName = this.getModuleName();
            result = result * 59 + ($moduleName == null ? 43 : $moduleName.hashCode());
            Object $driverName = this.getDriverName();
            result = result * 59 + ($driverName == null ? 43 : $driverName.hashCode());
            Object $address = this.getAddress();
            result = result * 59 + ($address == null ? 43 : $address.hashCode());
            Object $stock = this.getStock();
            result = result * 59 + ($stock == null ? 43 : $stock.hashCode());
            Object $username = this.getUsername();
            result = result * 59 + ($username == null ? 43 : $username.hashCode());
            Object $password = this.getPassword();
            result = result * 59 + ($password == null ? 43 : $password.hashCode());
            Object $superEntityClass = this.getSuperEntityClass();
            result = result * 59 + ($superEntityClass == null ? 43 : $superEntityClass.hashCode());
            result = result * 59 + Arrays.deepHashCode(this.getSuperEntityColumns());
            result = result * 59 + Arrays.deepHashCode(this.getTablePrefix());
            result = result * 59 + Arrays.deepHashCode(this.getFieldPrefix());
            result = result * 59 + Arrays.deepHashCode(this.getInclude());
            result = result * 59 + Arrays.deepHashCode(this.getExclude());
            result = result * 59 + (this.isControllerMappingHyphenStyle() ? 79 : 97);
            Object $outputDir = this.getOutputDir();
            result = result * 59 + ($outputDir == null ? 43 : $outputDir.hashCode());
            result = result * 59 + (this.isEntityTableFieldAnnotationEnable() ? 79 : 97);
            return result;
        }

        public String toString() {
            return "MybatisPlusGenerator.GeneratorModel(author=" + this.getAuthor() + ", parent=" + this.getParent() + ", moduleName=" + this.getModuleName() + ", driverName=" + this.getDriverName() + ", address=" + this.getAddress() + ", stock=" + this.getStock() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ", superEntityClass=" + this.getSuperEntityClass() + ", superEntityColumns=" + Arrays.deepToString(this.getSuperEntityColumns()) + ", tablePrefix=" + Arrays.deepToString(this.getTablePrefix()) + ", fieldPrefix=" + Arrays.deepToString(this.getFieldPrefix()) + ", include=" + Arrays.deepToString(this.getInclude()) + ", exclude=" + Arrays.deepToString(this.getExclude()) + ", controllerMappingHyphenStyle=" + this.isControllerMappingHyphenStyle() + ", outputDir=" + this.getOutputDir() + ", entityTableFieldAnnotationEnable=" + this.isEntityTableFieldAnnotationEnable() + ")";
        }
    }
}
